﻿using Sidvall.Security;
using Sidvall.Serialization;
using Sidvall.WorkItemManager.Business;
using Sidvall.WorkItemManager.Net.Services.V1;
using System.Threading.Tasks;

namespace Sidvall.WorkItemManager
{
    public partial class SystemContext
    {
        #region Public Members

        #region AuthenticationStrategy

        public Sidvall.Security.AuthenticationStrategy AuthenticationStrategy
        {
            get
            {
                return Sidvall.SystemContext.Current.AuthenticationStrategyManager?.AuthenticationStrategy as Sidvall.Security.AuthenticationStrategy;
            }
        }

        #endregion
        #region DataPortalStrategyFacade

        public Sidvall.DataPortal.DataPortalStrategy DataPortalStrategyFacade
        {
            get
            {
                if (this.DataPortalStrategy as Sidvall.DataPortal.DataPortalStrategy == null)
                {
                    lock (_Mutex)
                    {
                        if (this.DataPortalStrategy as Sidvall.DataPortal.DataPortalStrategy == null)
                        {
                            var item = new Sidvall.DataPortal.DataPortalStrategy()
                            {
                                MasterAuthenticationStrategy = this.AuthenticationStrategy,
                                ServerConnectionProvider = this.ServerConnectionProvider,
                            };
                            this.DataPortalStrategy = item;
                        }
                    }
                }
                return this.DataPortalStrategy as Sidvall.DataPortal.DataPortalStrategy;
            }
        }

        #endregion
        #region ServerConnectionProvider

        private System.Lazy<ServerConnectionProvider> _ServerConnectionProvider = new System.Lazy<ServerConnectionProvider>();
        public ServerConnectionProvider ServerConnectionProvider
        {
            get
            {
                return _ServerConnectionProvider.Value;
            }
        }

        #endregion
        #region UserConfiguration

        private UserConfiguration _UserConfiguration;
        public UserConfiguration UserConfiguration
        {
            get
            {
                return _UserConfiguration;
            }
            set
            {
                _UserConfiguration = GetValidConfiguration(value);
                InitializeAuthenticationStrategy();
            }
        }

        #endregion
        #region UserInfo

        private UserInfo _UserInfo;
        public UserInfo UserInfo
        {
            get
            {
                return _UserInfo;
            }
            set
            {
                _UserInfo = value;
            }
        }

        #endregion
        #region Version

        private string _Version;
        public string Version
        {
            get
            {
                return _Version;
            }
            set
            {
                _Version = GetValidVersion(value);
            }
        }

        #endregion

        #region AddServerConnection

        public Sidvall.DataPortal.ServerConnection AddServerConnection(Sidvall.WorkItemManager.Net.Services.V1.ServerConnection serverConnection)
        {
            return AddServerConnection(serverConnection, null);
        }
        public Sidvall.DataPortal.ServerConnection AddServerConnection(Sidvall.WorkItemManager.Net.Services.V1.ServerConnection serverConnection, string key)
        {
            var item = GetServerConnection(serverConnection, key);
            if (item != null)
                this.DataPortalStrategyFacade.ServerConnections.Add(item);
            return item;
        }

        #endregion
        #region AddSqlServerConnection

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public Sidvall.DataPortal.ServerConnection AddSqlServerConnection(string connectionString)
        {
            return AddSqlServerConnection(connectionString, null);
        }
        public Sidvall.DataPortal.ServerConnection AddSqlServerConnection(string connectionString, string key)
        {
            var item = GetSqlServerConnection(connectionString, key);
            this.DataPortalStrategyFacade.ServerConnections.Add(item);
            return item;
        }

        #endregion
        #region AddWebServiceConnection

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public Sidvall.DataPortal.ServerConnection AddWebServiceConnection(string address)
        {
            return AddWebServiceConnection(address, null);
        }
        public Sidvall.DataPortal.ServerConnection AddWebServiceConnection(string address, string key)
        {
            var item = GetWebServiceConnection(address, key);
            this.DataPortalStrategyFacade.ServerConnections.Add(item);
            return item;
        }

        #endregion
        #region GetServerConnection

        public Sidvall.DataPortal.ServerConnection GetServerConnection(Sidvall.WorkItemManager.Net.Services.V1.ServerConnection serverConnection)
        {
            return GetServerConnection(serverConnection, null);
        }
        public Sidvall.DataPortal.ServerConnection GetServerConnection(Sidvall.WorkItemManager.Net.Services.V1.ServerConnection serverConnection, string key)
        {
            if (serverConnection == null)
                return null;
            switch (serverConnection.ConnectionTypeId)
            {
                case Sidvall.WorkItemManager.Data.ConnectionType.RemoteAccess:
                    return GetWebServiceConnection(serverConnection.RemoteAddress, key);
                default:
                    return GetSqlServerConnection(serverConnection.ConnectionString, key);
            }
        }

        #endregion
        #region GetSqlServerConnection

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public Sidvall.DataPortal.ServerConnection GetSqlServerConnection(string connectionString, string key)
        {
            return Sidvall.DataPortal.ServerConnectionManager.GetSqlServerConnection(connectionString, "Sidvall.WorkItemManager.Data.Entity", key, null,
                "Sidvall.WorkItemManager.Data.Entity.Model.StorageManagerFactory, Sidvall.WorkItemManager.Data.Entity", null);
        }

        #endregion
        #region GetWebServiceConnection

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public Sidvall.DataPortal.ServerConnection GetWebServiceConnection(string address, string key)
        {
            return Sidvall.DataPortal.ServerConnectionManager.GetWebServiceConnection(address, key, null, null);
        }

        #endregion

        #region InitializeAuthenticationStrategy

        public void InitializeAuthenticationStrategy()
        {
            if (this.AuthenticationStrategy == null)
                return;
            this.AuthenticationStrategy.AuthorityTokenEndpoint = Sidvall.WorkItemManager.Security.SecurityManager.AuthorityTokenEndpoint;
            this.AuthenticationStrategy.ClientId = Sidvall.WorkItemManager.Configuration.SettingsManager.STSClientIdResolved;
            this.AuthenticationStrategy.ClientSecret = Sidvall.WorkItemManager.Configuration.SettingsManager.STSClientSecretResolved;
        }

        #endregion
        #region InitializeSqlServer

        public void InitializeSqlServer(string connectionString)
        {
            this.DataPortalStrategyFacade.ServerConnections.Clear();
            AddSqlServerConnection(connectionString);
        }

        #endregion

        #region LoadUserInfoAsync

        public async Task<UserInfo> LoadUserInfoAsync()
        {
            UserInfo item;

            if (Sidvall.WorkItemManager.Security.SecurityManager.CanConnectToServer)
            {
                item = await Sidvall.SystemContext.Current.AuthenticationManager.GetUserInfoAsync(Sidvall.WorkItemManager.Security.SecurityManager.AuthorityUserInfoEndpoint,
                    Sidvall.WorkItemManager.SystemContext.Current.AuthenticationStrategy.CurrentAuthenticationHeader.Parameter).ConfigureAwait(false);
            }
            else
            {
                item = new Sidvall.Security.UserInfo();
                item.SetName("local");
            }
            this.UserInfo = item;
            return this.UserInfo;
        }

        #endregion
        #region GetServerContentAsync

        public async Task<ServerContent> GetServerContentAsync(int? serverConnectionId)
        {
            ServerContent item;

            var runLocal = Sidvall.WorkItemManager.SystemContext.Current.DataPortalStrategyFacade.RunLocal(serverConnectionId.ToString());
            if (runLocal)
            {
                item = Sidvall.Security.SecurityManager.CreateServerContent("local");
            }
            else
            {
                var client = Sidvall.WorkItemManager.SystemContext.Current.DataPortalStrategyFacade.GetHttpClient(serverConnectionId.ToString());
                item = await Sidvall.Security.SecurityManager.GetServerContentAsync("api/V1/WorkItemManagerServerContent/GetItem",
                    Sidvall.WorkItemManager.SystemContext.Current.AuthenticationStrategy, client).ConfigureAwait(false);
            }
            return item;
        }

        #endregion

        #region LoadUserConfigurationAsync

        public async Task<UserConfiguration> LoadUserConfigurationAsync()
        {
            string content;

            content = null;
            try
            {
                if (await Sidvall.SystemContext.Current.UserStorageManager.FileExistsAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.ConfigFilePath).ConfigureAwait(false))
                    content = await Sidvall.SystemContext.Current.UserStorageManager.ReadAllTextAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.ConfigFilePath).ConfigureAwait(false);
            }
            catch (System.Exception)
            {
                content = null;
            }
            return LoadUserConfiguration(content);
        }

        #endregion
        #region LoadUserConfiguration

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public UserConfiguration LoadUserConfiguration(string content)
        {
            UserConfiguration configuration;

            configuration = null;
            try
            {
                if (!string.IsNullOrWhiteSpace(content))
                    configuration = Sidvall.Serialization.SerializerManager.Current.Deserialize<UserConfiguration>(content);
            }
            catch
            {
                configuration = null;
            }
            return LoadUserConfiguration(configuration);
        }
        public UserConfiguration LoadUserConfiguration(UserConfiguration configuration)
        {
            configuration = GetValidConfiguration(configuration);
            foreach (var serverConnection in configuration.ServerConnections.Items)
                serverConnection.IsLoaded = false;
            this.UserConfiguration = configuration;

            return this.UserConfiguration;
        }

        #endregion
        #region SaveUserConfigurationAsync

        public async Task<UserConfiguration> SaveUserConfigurationAsync(UserConfiguration configuration)
        {
            string content;
            int iMax;

            configuration = GetValidConfiguration(configuration);
            iMax = configuration.ServerConnections.Items.Count;
            for (int i = 0; i < iMax; i++)
            {
                configuration.ServerConnections.Items[i].ServerConnectionId = i + 1;
                configuration.ServerConnections.Items[i].UserConfigurationId = configuration.UserConfigurationId.Value;
            }
            content = Sidvall.Serialization.SerializerManager.Current.SerializeObject(configuration);
            await Sidvall.SystemContext.Current.UserStorageManager.WriteAllTextAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.ConfigFilePath, content).ConfigureAwait(false);
            this.UserConfiguration = configuration;

            return this.UserConfiguration;
        }

        #endregion

        #region LoadVersionAsync

        public async Task<string> LoadVersionAsync()
        {
            string version;

            version = null;
            try
            {
                if (await Sidvall.SystemContext.Current.UserStorageManager.FileExistsAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.VersionFilePath).ConfigureAwait(false))
                    version = await Sidvall.SystemContext.Current.UserStorageManager.ReadAllTextAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.VersionFilePath).ConfigureAwait(false);
            }
            catch (System.Exception)
            {
                version = null;
            }
            this.Version = version;

            return this.Version;
        }

        #endregion
        #region SaveVersionAsync

        public async Task<string> SaveVersionAsync(string version)
        {
            version = GetValidVersion(version);
            await Sidvall.SystemContext.Current.UserStorageManager.WriteAllTextAsync(Sidvall.WorkItemManager.Configuration.SettingsManager.VersionFilePath, version).ConfigureAwait(false);
            this.Version = version;

            return this.Version;
        }

        #endregion

        #endregion
        #region Private Members

        #region GetValidConfiguration

        private static UserConfiguration GetValidConfiguration(UserConfiguration item)
        {
            if (item == null)
            {
                item = new UserConfiguration()
                {
                    StartPageId = Data.PageType.Dashboard,
                };
            }
            if (item.UserConfigurationId == null)
                item.UserConfigurationId = 1;
            if (string.IsNullOrWhiteSpace(item.Name))
                item.Name = "Default";
            if (item.ServerConnections == null)
                item.ServerConnections = new ServerConnectionCollectionItem();

            return item;
        }

        #endregion
        #region GetValidVersion

        private static string GetValidVersion(string version)
        {
            if (string.IsNullOrWhiteSpace(version))
                return "1.0";
            return version;
        }

        #endregion

        #endregion
    }
}